package org.jjj.user.service.impl;

import org.apache.commons.lang3.StringUtils;
import org.jjj.basic.utils.ResultAjax;
import org.jjj.basic.utils.SmsUtil;
import org.jjj.basic.utils.StrUtils;
import org.jjj.basic.utils.VerifyCodeUtils;
import org.jjj.user.domain.Logininfo;
import org.jjj.user.dto.PhoneSmsLoginDTO;
import org.jjj.user.dto.RetrievepasswordDTO;
import org.jjj.user.dto.VerifyCodeDTO;
import org.jjj.user.mapper.LogininfoMapper;
import org.jjj.user.service.IVerifyCodeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private LogininfoMapper logininfoMapper;

    /**
     * 获取图形验证码
     * @param key
     * @return
     */
    @Override
    public String getImgeCode(String key) {
        //1.生成四位验证码字符串
        String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
        //2.将验证码放入redis中，设置过期时间为三分钟
        redisTemplate.opsForValue().set(key,verifyCode,3, TimeUnit.MINUTES);
        //3.把生成的验证码合并到图片中并加密为base64数据返回给前端
        try {
            String base64ImageCode = VerifyCodeUtils.VerifyCode(100, 40, verifyCode);
            return base64ImageCode;
        } catch (IOException e) {
            e.printStackTrace();
            return e.getMessage();
        }
    }

    /**
     * 发送注册时的短信验证码
     * @param dto
     * @return
     */
    @Override
    public ResultAjax getRegisterSmsCode(VerifyCodeDTO dto) {
        //1.参数的非空校验
        String mobile = dto.getMobile();
        String imageCode = dto.getImageCode();//前端输入的图形验证码
        String imageCodeKey = dto.getImageCodeKey();//图形验证码存入redis中前端生成的key
        if (StringUtils.isEmpty(mobile)||StringUtils.isEmpty(imageCode)||StringUtils.isEmpty(imageCodeKey)){
            return ResultAjax.me().setSuccess(false).setMessage("请填写完整信息后再提交注册！");
        }
        //2.验证图形验证码输入是否正确，这里验证不区分大小写
        //之前生成的存入redis中的图形验证码
        String generateCode = (String)redisTemplate.opsForValue().get(imageCodeKey);
        if (!imageCode.equalsIgnoreCase(generateCode)){
            return ResultAjax.me().setSuccess(false).setMessage("图形验证码输入不正确！");
        }
        //3.验证手机号是否已经注册过：通过手机号去后端数据库查询登录用户信息是否存在
        Logininfo logininfo = logininfoMapper.getRegisterUserByPhone(mobile);
        if (Objects.nonNull(logininfo)){
            return ResultAjax.me().setSuccess(false).setMessage("该手机号已被注册,请直接登录使用");
        }
        //4.生成手机验证码
        //验证是否已经发送过验证码（这里如果上一次的验证码已经过期相当于没有发送过）
        //这里手机验证码也是存放在redis中的，而一个手机号不仅仅只有一种验证码，所以不能仅仅用手机号作为存数据的key
        String key = "register_sms_code_"+mobile;
        return getPhoneVerifyCode(key);
    }



    /**
     * 绑定微信账号时发送短信获取手机验证码
     * @param dto
     * @return
     */
    @Override
    public ResultAjax getBinderSmsCode(VerifyCodeDTO dto) {
        //1.参数的非空校验
        String mobile = dto.getMobile();
        if (StringUtils.isEmpty(mobile)){
            return ResultAjax.me().setSuccess(false).setMessage("请填写手机号再获取验证码！");
        }
        //2.生成手机验证码
        //验证是否已经发送过验证码（这里如果上一次的验证码已经过期相当于没有发送过）
        //这里手机验证码也是存放在redis中的，而一个手机号不仅仅只有一种验证码，所以不能仅仅用手机号作为存数据的key
        String key = "binder_sms_code_"+mobile;
        //从redis中取数据
        return getPhoneVerifyCode(key);
    }

    /**
     * 手机验证码登录，发送手机验证码信息
     * @param dto
     * @return
     */
    @Override
    public ResultAjax getPhoneSmsCode(PhoneSmsLoginDTO dto) {
        //1.参数的非空校验
        String mobile = dto.getMobile();
        if (StringUtils.isEmpty(mobile)){
            return ResultAjax.me().setSuccess(false).setMessage("请填写手机号再获取验证码！");
        }
        //2.生成手机验证码
        //验证是否已经发送过验证码（这里如果上一次的验证码已经过期相当于没有发送过）
        //这里手机验证码也是存放在redis中的，而一个手机号不仅仅只有一种验证码，所以不能仅仅用手机号作为存数据的key
        String key = "phone_sms_code_"+mobile;
        //从redis中取数据
        return getPhoneVerifyCode(key);
    }

    /**
     * 找回密码时获取发送的手机验证码
     * @param dto
     * @return
     */
    @Override
    public ResultAjax getRetrievepasswordSmsCode(RetrievepasswordDTO dto) {
        //1.参数的非空校验
        String mobile = dto.getMobile();
        if (StringUtils.isEmpty(mobile)){
            return ResultAjax.me().setSuccess(false).setMessage("请填写手机号再获取验证码！");
        }
        //2.生成手机验证码
        //验证是否已经发送过验证码（这里如果上一次的验证码已经过期相当于没有发送过）
        //这里手机验证码也是存放在redis中的，而一个手机号不仅仅只有一种验证码，所以不能仅仅用手机号作为存数据的key
        String key = "retrievepassword_sms_code_"+mobile;
        //返回验证码
        return getPhoneVerifyCode(key);
    }

    /**
     * 抽取出的获取短信验证码的方法，减少代码重复率
     * @param key
     * @return
     */
    private ResultAjax getPhoneVerifyCode(String key) {
        //定义一个变量来装获得的手机验证码
        String smsCode = "";
        //1.从redis中取数据
        String smsCodeOfRedis = (String) redisTemplate.opsForValue().get(key);

        if (StringUtils.isEmpty(smsCodeOfRedis)) {
            //2.如果redis中没有，就重新生成验证码
            smsCode = StrUtils.getRandomString(6);
        } else {
            //3.如果存在就判断是否过了重发时间，没过就提示错误信息
            Long sendTime = Long.parseLong(smsCodeOfRedis.split(":")[1]);//发送时间
            if (System.currentTimeMillis() - sendTime < 60 * 1000) {
                return ResultAjax.me().setSuccess(false).setMessage("请不要频繁发送验证码信息！");
            }
            //4.过了就还用原来没有过期的验证码
            smsCode = smsCodeOfRedis.split(":")[0];
        }
        //5.将手机验证码存入redis中一份，并重新设置过期时间为5分钟
        redisTemplate.opsForValue().set(key, smsCode + ":" + System.currentTimeMillis(), 5, TimeUnit.MINUTES);
        //6.发短信给注册用户：调用三方接口
        //短信内容
        String content = "您的验证码是%s,请在%s分钟内填写！";
//        SmsUtil.sendSms(mobile,String.format(content,smsCode,5));
        System.out.println(String.format(content, smsCode, 5));
        return ResultAjax.me();
    }
}
